/*
	ahci_main.c

	contains the boot AHCI initialisation process

	Author: Aidan Goddard 4/1/2014
*/

#include"ahci.h"
#include"../ACDM/ACDM_buffer.h"


// function to draw the results table
static void DrawResults(HWND hwnd, char *results, uint32_t *result_offsets, uint32_t list_length, int list_top, int list_highlighted)
{
	// clamp values
	if(list_highlighted < 0)
	{
		list_highlighted = 0;
	}
	if(list_length < 11 &&  list_highlighted < 0)
	{
		list_top = 0;
		list_highlighted = 0;
	}


	// clear the portion of the screen containing the table
	char *hwnd_buffer = (char*)ACDMWindowGetBufferAddress(hwnd);
	int i;
	for(i = 1440; i < 3680; i += 2)
	{
		hwnd_buffer[i] = 0;
	}

	// draw the table
	WriteStringToBuffer(hwnd & 0x1ff, 1444, "|                         Directory Name                               |");
	WriteStringToBuffer(hwnd & 0x1ff, 1604, "------------------------------------------------------------------------");
	WriteStringToBuffer(hwnd & 0x1ff, 3524, "------------------------------------------------------------------------");
	for(i = 11; i < 22; i++)
	{
		WriteStringToBuffer(hwnd & 0x1ff, 160 * i + 4, "|                                                                      |");
	}

	// set normal background
	char *background_ptr = (char*)ACDMWindowGetBufferAddress(hwnd);
	for(i = 1; i < 3680; i += 2)
	{
		*(char*)(background_ptr + i) = 0x1f;
	}

	// if no entries, then exit
	if(list_length == 0)
	{
		return;
	}

	// for each item in the list
	uint32_t c_index = 0;
	for(i = 0; i < 11; i++)
	{
		// check for current pos in list is larger than list length
		if(i >= list_length)
		{
			continue;
		}

		// get offset of string to print
		uint32_t s_offset = result_offsets[list_top + i];
		char *string_to_print = (char*)&(results[s_offset]);

		// print it
		WriteStringToBuffer(hwnd & 0x1ff, 160 * i + 1768, "%s", string_to_print);
	}

	// highlight selected proc
	if(list_length > 0)
	{
		char *high_ptr = (char*)(background_ptr + (1765 + 160 * list_highlighted));
		for(i = 0; i < 72*2; i += 2)
		{
			high_ptr[i] = 0x8f;
		}
	}

	// determine if scroll bar is necessary
	if(list_length > 11)
	{
		// draw the scroll bar base
		char *b_ptr = (char*)(background_ptr + 1908); // 948
		for(i = 0; i < 11; i++)
		{
			*(char*)(b_ptr + 160 * i) = 176;
		}

		// draw the scroll indicator
		// determine ratio of slots to each proc.
		double rstp = (double)11 / (double)(list_length - 11);

		// work out which slot to start on
		double start_slot = (double)list_top * rstp;

		// draw it
		int i_start_slot = (int)start_slot;
		if(i_start_slot > 10)
		{
			i_start_slot = 10;
		}
		*(char*)(b_ptr + 160 * i_start_slot) = 178;
	}

	// finished
	return;
}


// ahci main process
void AHCI_main(void)
{
/*
	// call driver init
	uint32_t error = AHCI_INIT();
	__KLIB__SleepThisThread(5000000);

	if(error != AHCI_INIT_SUCCESS)
	{
		// log error message
		if(error == AHCI_INIT_FAIL_NO_DEVICES)
		{
			ACDMPrintLog("AHCI: Error init failed: AHCI_INIT_FAIL_NO_DEVICES", 50);
		}
		else if(error == AHCI_INIT_FAIL_NO_ISR)
		{
			ACDMPrintLog("AHCI: Error init failed: AHCI_INIT_FAIL_NO_ISR", 46);
		}

		// terminate
		AHCI_DROP();
		__KLIB__KillThisProcess(error);
	}
	else
	{
		ACDMPrintLog("AHCI: Init success", 18);
	}

	// call FAT32 init
	error = FAT32_INIT();
	if(error != FAT32_SUCCESS)
	{
		// log error message
		if(error == FAT32_IS_FAT_12)
		{
			ACDMPrintLog("FAT32: Error filesystem is FAT12", 32);
		}
		else if(error == FAT32_IS_FAT_16)
		{
			ACDMPrintLog("FAT32: Error filesystem is FAT16", 32);
		}
		else if(error == FAT32_CLUSTER_TOO_LARGE)
		{
			ACDMPrintLog("FAT32: Error cluster size too large", 35);
		}

		// terminate
		AHCI_DROP();
		__KLIB__KillThisProcess(error);
	}
	else
	{
		ACDMPrintLog("FAT32: Init success", 18);
	}
*/
	// set up demo explorer window
	HWND hwnd = ACDMCreateStaticWindow(__KLIB__RCGetPID(), "AHCI demo", 9);
	ACDMWindowShow(hwnd);
	char *hwnd_buffer = (char*)ACDMWindowGetBufferAddress(hwnd);

	// setup file reading window
	HWND hwnd2 = ACDMCreateStaticWindow(__KLIB__RCGetPID(), "AHCI demo - read file", 21);
	char *hwnd2_buffer = (char*)ACDMWindowGetBufferAddress(hwnd2);

	// set the background colour
	int i;
	for(i = 1; i < 3680; i += 2)
	{
		hwnd_buffer[i] = 0x1f;
		hwnd2_buffer[i] = 0x1f;
	}

	// draw title and instruction
	WriteStringToBuffer(hwnd & 0x1ff, 324, "Application to demonstrate access to the FAT32 volume on an AHCI SATA disk");
	//WriteStringToBuffer(hwnd & 0x1ff, 484, "Please enter directory to search (\"/\" = root):");
	//int c = WriteStringToBuffer(hwnd & 0x1ff, 644, "->");
	//SetCursor(hwnd & 0x1ff, c/2, 1);

	// draw results table
	DrawResults(hwnd, NULL, NULL, 0, 0, 0);

	// first draw to screen
	ACDMWindowUpdate(hwnd);

	// somewhere to store the user input
	char dir_buffer[512];
	uint32_t dir_buffer_index = 1;
	dir_buffer[0] = '/';
	char dirs_buffer[16384];
	uint32_t d_offsets[256];

	// display control vars
	int list_top = 0;
	int list_highlighted = 0;
	int list_selected = 0;
	int list_length = 0;

	// force input for first go
	uint8_t input = 0x08;

	// main input loop
	while(1)
	{
		// check for newline char returned (indicates return pressed) or backspace key pressed
		if(input == '\n' || input == 0x08)
		{


/*
			// reset list selector
			list_selected = 0;

			// disable the cursor
			SetCursor(hwnd & 0x1ff, 2000, 0);

			// zero the end of the dir buffer
			dir_buffer[dir_buffer_index] = 0;
*/
			// check which input
			if(input == '\n')
			{
				// get the string of the next directory
				char *next_dir = (char*)&(dirs_buffer[d_offsets[list_selected]]);

				// check if is .
				if(next_dir[0] == '.' && next_dir[1] == 0)
				{
					// do nothing
				}
				// check if is ..
				else if(next_dir[0] == '.' && next_dir[1] == '.' && next_dir[2] == 0)
				{
					input = 0x08;
				}
				// otherwise add it to the dir string
				else
				{
					int k;
					for(k = 0; next_dir[k] != 0; k++)
					{
						dir_buffer[dir_buffer_index++] = next_dir[k];
					}
					dir_buffer[dir_buffer_index++] = '/';
					dir_buffer[dir_buffer_index] = 0;
				}
			}
			if(input == 0x08 && dir_buffer_index > 1)
			{
				// remove chars to the previous '/' char
				dir_buffer_index--;
				while(dir_buffer[dir_buffer_index - 1] != '/')
				{
					dir_buffer_index--;
				}
				dir_buffer[dir_buffer_index] = 0;
			}


			// get directory length count
			uint32_t returned_dirs_length = 0;
			uint32_t e = BootGetDirCount(dir_buffer, &returned_dirs_length);
			if(e == FAT32_NO_PATH)
			{
				WriteStringToBuffer(hwnd & 0x1ff, 1124, "error: directory does not exist");
			}
			else
			{
				WriteStringToBuffer(hwnd & 0x1ff, 1124, "                               ");
			}

			WriteStringToBuffer(hwnd & 0x1ff, 804, "returned char length: %u           ", returned_dirs_length);
			WriteStringToBuffer(hwnd & 0x1ff, 964, "                                                                               ");
			WriteStringToBuffer(hwnd & 0x1ff, 964, "directory: %s", dir_buffer);

			// get the directories
			uint32_t dirs_count = 0;
			BootGetDirs(dir_buffer, dirs_buffer, returned_dirs_length);

			// get directory offsets
			d_offsets[0] = 0;
			uint32_t k;

			for(k = 0; k < returned_dirs_length; k++)
			{
				if(dirs_buffer[k] == ';')
				{
					dirs_buffer[k] = 0;
					d_offsets[++dirs_count] = k + 1;
				}
			}
			list_length = dirs_count;

			// draw the list
			list_highlighted = 0;
			list_selected = 0;
			DrawResults(hwnd, dirs_buffer, d_offsets, list_length, list_top, list_highlighted);
		}

		// check for o key - open file
		if(input == 'o')
		{
			// get the file path to open
			// get the string of the next directory
			char *next_dir = (char*)&(dirs_buffer[d_offsets[list_selected]]);

			// check if is .
			if(next_dir[0] == '.' && next_dir[1] == 0)
			{
				// do nothing
			}
			// check if is ..
			else if(next_dir[0] == '.' && next_dir[1] == '.' && next_dir[2] == 0)
			{
				// do nothing
			}
			// otherwise add it to the dir string
			else
			{
				int k, j;
				for(k = 0; next_dir[k] != 0; k++)
				{
					dir_buffer[dir_buffer_index++] = next_dir[k];
				}
				//dir_buffer[dir_buffer_index++] = '/';
				dir_buffer[dir_buffer_index] = 0;

				WriteStringToBuffer(hwnd & 0x1ff, 964, "                                                                               ");
				WriteStringToBuffer(hwnd & 0x1ff, 964, "file: %s", dir_buffer);

				// read the file into the buffer
				char file_buffer[1024];
				uint32_t e = BootReadFile(dir_buffer, file_buffer, 0, 1024);

				if(e == FAT32_SUCCESS)
				{
					// hide this window
					ACDMWindowHide(hwnd);

					// display contents of the buffer into window 2
					for(k = 0, j = 0; k < 1024 && j < 3680; k++)
					{
						// check for new line char
						if(file_buffer[k] == '\n')
						{
							// set j to the next line
							j += 160;

							// move to the start of the line
							j = j / 160;
							j = j * 160;
						}
						else
						{
							// print it
							hwnd2_buffer[j] = file_buffer[k];
							j += 2;
						}
					}


					// show the read window
					ACDMWindowShow(hwnd2);
					ACDMGiveFocus(hwnd2);

					// input loop
					while(1)
					{
						// get input
						input = ACDMWindowWaitForChar(hwnd2);

						// check for backspace
						if(input == 0x08)
						{
							break;
						}
					}

					// finished with that window
					// clear it
					for(k = 0; k < 3680; k += 2)
					{
						hwnd2_buffer[k] = 0;
					}

					// switch back to main window
					ACDMWindowHide(hwnd2);
					ACDMWindowShow(hwnd);
					ACDMGiveFocus(hwnd);
				}

				// remove dir chars to the previous '/' char
				while(dir_buffer[dir_buffer_index - 1] != '/')
				{
					dir_buffer_index--;
				}
				dir_buffer[dir_buffer_index] = 0;

			}
		}

/*
		// check for backspace char
		else if(input == 0x08)
		{
			// check pos is not 0
			if(dir_buffer_index > 0)
			{
				// decrease buffer index
				dir_buffer_index--;

				// zero password field
				dir_buffer[dir_buffer_index] = 0;

				// clear the character at the current position
				hwnd_buffer[c + (dir_buffer_index * 2)] = 0;
				SetCursor(hwnd & 0x1ff,  c/2 + dir_buffer_index, 1);
			}
		}
*/
		// down arrow
		else if(input == 0xc2)
		{
			if(list_selected < list_length - 1 && list_length > 0)
			{
				list_selected++;
			}
		}

		// up arrow
		else if(input == 0xc1)
		{
			if(list_selected > 0 && list_length > 0)
			{
				list_selected--;
			}
		}

/*
		// check if is a printable ASCII char
		else if(input >= 32 && input <= 254)
		{
			// check if password field is not full
			if(dir_buffer_index < 70)
			{
				// save the char to the field
				dir_buffer[dir_buffer_index] = input;

				// print the character
				hwnd_buffer[c + (dir_buffer_index * 2)] = input;
				SetCursor(hwnd & 0x1ff,  c/2 + dir_buffer_index + 1, 1);

				// increase buffer index
				dir_buffer_index++;
			}
		}
*/

		// otherwise ignore it
		else
		{
		}

		// calculate window and highlighted row
		if(list_selected >= (list_top + 11))
		{
			list_top++;
		}
		if(list_selected < list_top)
		{
			list_top--;
		}

		list_highlighted = list_selected - list_top;

		// update the video buffer
		DrawResults(hwnd, dirs_buffer, d_offsets, list_length, list_top, list_highlighted);
		ACDMWindowUpdate(hwnd);

		// get input
		input = ACDMWindowWaitForChar(hwnd);
	}


	uint32_t dirs_length;
	BootGetDirCount("/", &dirs_length);

	char dirs[2048];

	uint32_t e = BootGetDirs("/", dirs, dirs_length);



	AHCI_DROP();






	// terminate
	__KLIB__KillThisProcess(0);
	return;
}




